/*
 * XTabbedPane.java
 * 
 * Copyright (c) 2006 - 2007
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.xfc.components;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.xfc.XApp;
import org.xfc.util.XListenerManager;
import org.xfc.util.XResources;
import org.xfc.util.XUtils;

import com.jgoodies.forms.layout.FormLayout;

/**
 * 
 * 
 * @author Devon Carew
 */
public class XTabbedPane
	extends JPanel
{
	private JTabbedPane 		tabbedPane;
	private XIconButton			closeButton;
	
	private List				tabList = new ArrayList();
	private XListenerManager	listenerManager = new XListenerManager();
	
	private XTabbedPaneTab		currentSelectedTab;
	
	private PropertyChangeListener	tabListener;
	
	
	/**
	 * Create a new tabbed pane.
	 */
	public XTabbedPane()
	{
		ChangeListener changeListener = new ChangeListener() {
			public void stateChanged(ChangeEvent event) {
				updateTabState();
			}
		};
		
		tabbedPane = new JTabbedPane();
		tabbedPane.addChangeListener(changeListener);
		tabbedPane.getModel().addChangeListener(changeListener);
		// The close button interferes with the tabbed pane's left and right arrow buttons.
		//tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
		
		XResources resources = XApp.getApp().getResources();
		
		ImageIcon stripIcon = resources.getIcon("/firefox/skin/classic/global/icons/close.png");
		ImageIcon[] icons = XUtils.splitImageIconStrip(stripIcon, 16);
		
		closeButton = new XIconButton(icons[0]);
		closeButton.setRolloverIcon(icons[1]);
		closeButton.setPushedIcon(icons[2]);
		closeButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				XTabbedPaneTab tab = getSelectedTab();
				
				if (tab != null && canCloseTab(tab))
					removeTab(tab);
			}
		});
		
		tabListener = new PropertyChangeListener() {
			public void propertyChange(PropertyChangeEvent event) {
				tabPropertyChanged(event);
			}
		};
		
		setLayout(new FormLayout(
			"min:grow pref 2",
			"2 pref min:grow"
		));
		
		add(closeButton, 	"2, 2");
		add(tabbedPane, 	"1, 1, 3, 3, f, f");
	}
	
	public void addTabbedPaneListener(XTabbedPaneListener listener)
	{
		listenerManager.addListener(listener);
	}
	
	public void removeTabbedPaneListener(XTabbedPaneListener listener)
	{
		listenerManager.removeListener(listener);
	}
	
	public void addTab(XTabbedPaneTab tab)
	{
		if (tab.getTitle() == null)
			throw new IllegalArgumentException("tab has no title");
		
		if (tab.getComponent() == null)
			throw new IllegalArgumentException("tab has no content component");
		
		tabList.add(tab);
		tabbedPane.addTab(tab.getTitle(), tab.getIcon(), tab.getComponent(), tab.getToolTipText());
		
		tab.addPropertyChangeListener(tabListener);
		
		listenerManager.notifyListeners("tabAdded", tab);
	}
	
	public int getIndexOfTab(XTabbedPaneTab tab)
	{
		return tabbedPane.indexOfComponent(tab.getComponent());
	}
	
	public void removeTabAt(int index)
	{
		XTabbedPaneTab tab = getTabAt(index);
		
		tabList.remove(index);
		tabbedPane.removeTabAt(index);
		
		tab.removePropertyChangeListener(tabListener);
		
		listenerManager.notifyListeners("tabRemoved", tab);
		
		updateTabState();
	}
	
	public void removeTab(XTabbedPaneTab tab)
	{
		int index = getIndexOfTab(tab);
		
		if (index >= 0)
			removeTabAt(index);
	}
	
	public XTabbedPaneTab getTabAt(int index)
	{
		if (index < tabList.size())
			return (XTabbedPaneTab)tabList.get(index);
		
		return null;
	}
	
	public int getTabCount()
	{
		return tabbedPane.getTabCount();
	}
	
	public int getSelectedIndex()
	{
		return tabbedPane.getSelectedIndex();
	}
	
	public void setSelectedIndex(int index)
	{
		tabbedPane.setSelectedIndex(index);
	}
	
	public XTabbedPaneTab getSelectedTab()
	{
		int index = getSelectedIndex();
		
		return index >= 0 ? getTabAt(index) : null;
	}
	
	public void setSelectedTab(XTabbedPaneTab tab)
	{
		int index = getIndexOfTab(tab);
		
		if (index >= 0)
			setSelectedIndex(index);
	}

	public JTabbedPane getJTabbedPane()
	{
		return tabbedPane;
	}
	
	
//	public Icon getIconAt(int index) {
//		return tabbedPane.getIconAt(index);
//	}
//
//	public String getTitleAt(int index) {
//		return tabbedPane.getTitleAt(index);
//	}
//
//	public String getToolTipTextAt(int index) {
//		return tabbedPane.getToolTipTextAt(index);
//	}
//
//	
//	public void setIconAt(int index, Icon icon) {
//		tabbedPane.setIconAt(index, icon);
//	}
//
//	public void setTitleAt(int index, String title) {
//		tabbedPane.setTitleAt(index, title);
//	}
//
//	public void setToolTipTextAt(int index, String toolTipText) {
//		tabbedPane.setToolTipTextAt(index, toolTipText);
//	}
	
	/**
	 * Ask the tabbed pane's listeners if it is OK to close the given tab.
	 * 
	 * @param tab
	 * @return whether the listeners OK the tab closing
	 */
	public boolean canCloseTab(XTabbedPaneTab tab)
	{
		if (!tab.isCloseableTab() || !tab.canClose())
			return false;
		
		List listeners = listenerManager.getListeners();
		
		for (int i = listeners.size() - 1; i >= 0; i--)
		{
			XTabbedPaneListener listener = (XTabbedPaneListener)listeners.get(i);
			
			// Ask the listener if it's OK to close the tab.
			if (!listener.tabClosing(tab))
				return false;
		}
		
		return true;
	}
	
	private void updateTabState()
	{
		XTabbedPaneTab tab = getSelectedTab();
		
		if (tab != null && tab.isCloseableTab())
			closeButton.setEnabled(true);
		else
			closeButton.setEnabled(false);
		
		// Check for a change in the tab selection.
		if (currentSelectedTab != tab)
		{
			XTabbedPaneTab oldSelectedTab = currentSelectedTab;
			
			currentSelectedTab = tab;
			
			if (oldSelectedTab != null)
				listenerManager.notifyListeners("tabDeselected", oldSelectedTab);
			
			if (currentSelectedTab != null)
				listenerManager.notifyListeners("tabSelected", currentSelectedTab);
		}
	}
	
	private void tabPropertyChanged(PropertyChangeEvent event)
	{
		String 			eventName = event.getPropertyName();
		XTabbedPaneTab 	sourceTab = (XTabbedPaneTab)event.getSource();
		
		// event name can be: title, icon, toolTipText, closeableTab
		
		if ("closeableTab".equals(eventName) && sourceTab == currentSelectedTab)
		{
			updateTabState();
		}
		else if ("title".equals(eventName))
		{
			tabbedPane.setTitleAt(getIndexOfTab(sourceTab), sourceTab.getTitle());
		}
		else if ("icon".equals(eventName))
		{
			tabbedPane.setIconAt(getIndexOfTab(sourceTab), sourceTab.getIcon());
		}
		else if ("toolTipText".equals(eventName))
		{
			tabbedPane.setToolTipTextAt(getIndexOfTab(sourceTab), sourceTab.getToolTipText());
		}
	}
	
}
